package com.zhr.controller;

import javafx.collections.ObservableList;
import javafx.geometry.Point2D;
import javafx.scene.control.ListView;
import javafx.scene.image.Image;
import javafx.scene.image.ImageView;
import javafx.scene.layout.*;
import javafx.stage.DirectoryChooser;
import javafx.stage.FileChooser;
import javafx.stage.Stage;

import java.io.File;
import java.io.FileFilter;
import java.io.FilenameFilter;
import java.net.URISyntaxException;
import java.net.URL;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;
import java.util.function.Predicate;
import java.util.stream.Stream;

public class ImageViewerController {
    //父组件
    public AnchorPane anchorPaneRoot;
    //工具栏组件
    public FlowPane flowPaneTool;
    //图片
    public ImageView imageView;
    //图片信息展示
    public ListView<String> listViewInfo;
    //每次图片放大系数
    private double added = 0.10;
    //每次旋转角度
    private double rotateAngle = 90.0;
    //放大图标...等等
    public ImageView imageViewBig;
    public ImageView imageViewSmall;
    public ImageView imageViewLast;
    public ImageView imageViewNext;
    public ImageView imageViewInfo;
    public ImageView imageViewNice;
    public ImageView imageViewRotateLeft;
    public ImageView imageViewRotateRight;
    public ImageView imageViewFullScreen;
    public ImageView imageViewReload;
    public ImageView imageViewOpenFile;
    public ImageView imageViewOpenDir;
    public ImageView imageViewOrigin;
    //父stage
    private Stage stage;
    private static final String DEFAULT_IMAGE_URL = "icons/default.png";
    private List<String> imgPaths = new ArrayList<>();
    //当前显示的图片url下表 -1 表示没有图片
    private int currentImgIndex = -1;
    private FileChooser fileChooser = new FileChooser();
    private DirectoryChooser directoryChooser = new DirectoryChooser();
    private FileChooser.ExtensionFilter filter =
            new FileChooser.ExtensionFilter("图片", "*.jpg", "*.png", "*.gif");

    public void init() {
        initImgList();
        initImageView();
        initImageViewInfoAndListViewInfo();
        initImageViewOrigin();
        initImageViewNice();
        initImageViewLast();
        initImageViewNext();
        initImageViewRotateLeft();
        initImageViewRotateRight();
        initImageViewFullScreen();
        initFlowPane();
        initImageViewBig();
        initImageViewSmall();
        initAnchorPaneRoot();
        initImageReload();
        initImageViewOpenFile();
        initImageViewOpenDir();
        initStage();
    }

    private void initImageViewOpenDir() {
        Image open = new Image("icons/folder-add.png");
        imageViewOpenDir.setImage(open);
        directoryChooser.setTitle("打开文件夹");
        imageViewOpenDir.setOnMouseClicked(event -> {
            File file = directoryChooser.showDialog(stage);
            File[] files = file.listFiles((dir, name) -> {
                String suffix = name.substring(name.lastIndexOf("."));
                Stream<String> stringStream = Stream.of(".jpg", ".png", ".gif");
                return stringStream.anyMatch(s -> s.equalsIgnoreCase(suffix));
            });
            if (files != null && files.length > 0) {
                imgPaths.clear();
                currentImgIndex = 0;
                Stream.of(files).forEach(e -> imgPaths.add(e.getAbsolutePath()));
                imageView.setImage(getImage(imgPaths.get(currentImgIndex)));
            }
        });
    }

    private void initImageViewOpenFile() {
        Image open = new Image("icons/open-image.png");
        imageViewOpenFile.setImage(open);
        fileChooser.setTitle("选择图片");
        imageViewOpenFile.setOnMouseClicked(event -> {
            fileChooser.getExtensionFilters().add(filter);
            List<File> list = fileChooser.showOpenMultipleDialog(stage);
            if (list != null && list.size() > 0) {
                imgPaths.clear();
                currentImgIndex = 0;
                list.forEach(e -> imgPaths.add(e.getAbsolutePath()));
                imageView.setImage(getImage(imgPaths.get(currentImgIndex)));
            }
        });
    }

    private void initImageViewOrigin() {
        Image fullScreen = new Image("icons/check-circle.png");
        imageViewOrigin.setImage(fullScreen);
        imageViewOrigin.setOnMouseClicked(event -> {
            Image image = imageView.getImage();
            double imageHeight = image.getHeight();
            double imageWidth = image.getWidth();
            imageView.setFitWidth(imageWidth);
            imageView.setFitHeight(imageHeight);
            updateImageViewLayout();
        });
    }

    private void initStage() {
        stage.widthProperty().addListener((observable, oldValue, newValue) -> {
            updateImageViewLayout();
            updateFlowPaneLayout();
        });
        stage.heightProperty().addListener((observable, oldValue, newValue) -> {
            updateImageViewLayout();
            updateFlowPaneLayout();
        });
        stage.fullScreenProperty().addListener((observable, oldValue, newValue) -> {
            //System.out.println("stage.fullScreenProperty。。。。。。。oldValue" + oldValue + " newValue" + newValue);
            //System.out.println(stage.isAlwaysOnTop());
            stage.setAlwaysOnTop(newValue);
            //System.out.println(stage.isAlwaysOnTop());
            if (newValue) {
                anchorPaneRoot.setStyle("-fx-background-color: black");
            } else {
                anchorPaneRoot.setBackground(Background.EMPTY);
            }
        });

    }

    private void initImageViewFullScreen() {
        Image fullScreen = new Image("icons/fullscreen.png");
        imageViewFullScreen.setImage(fullScreen);
        imageViewFullScreen.setOnMouseClicked(event -> {
            stage.setFullScreen(!stage.isFullScreen());
        });
    }

    private void initImageViewInfoAndListViewInfo() {
        Image info = new Image("icons/info-circle.png");
        imageViewInfo.setImage(info);
        imageViewInfo.setOnMouseClicked(event -> {
            listViewInfo.setVisible(!listViewInfo.isVisible());
        });
        listViewInfo.setBorder(Border.EMPTY);
        File file;
        if (currentImgIndex == -1) {
            file = new File(DEFAULT_IMAGE_URL);
        } else {
            file = new File(imgPaths.get(currentImgIndex));
        }
        ObservableList<String> items = listViewInfo.getItems();
        items.clear();
        items.add("图片大小:" + getFileUnit(file.length()));
        items.add("原始大小(长宽):" + imageView.getImage().getHeight() + "x" + imageView.getImage().getWidth());
        items.add("当前大小(长宽):" + imageView.getFitHeight() + "x" + imageView.getFitWidth());
    }

    private String getFileUnit(long length) {
        if (length < 1024) {
            return length + "B";
        } else if (length < 1024 * 1024) {
            return String.format("%.2f", length / 1024.0) + "KB";
        } else {
            return String.format("%.2f", length / 1024.0 / 1024.0) + "MB";
        }
    }

    private void initImageViewRotateRight() {
        Image rotateRight = new Image("icons/rotate-right.png");
        imageViewRotateRight.setImage(rotateRight);
        imageViewRotateRight.setOnMouseClicked(event -> {
            double v = imageView.rotateProperty().get();
            imageView.rotateProperty().set(v + rotateAngle);
        });
    }

    private void initImageViewRotateLeft() {
        Image rotateLeft = new Image("icons/rotate-left.png");
        imageViewRotateLeft.setImage(rotateLeft);
        imageViewRotateLeft.setOnMouseClicked(event -> {
            double v = imageView.rotateProperty().get();
            imageView.rotateProperty().set(v - rotateAngle);
        });
    }

    private void initImageViewNext() {
        Image next = new Image("icons/right-circle.png");
        imageViewNext.setImage(next);
        imageViewNext.setOnMouseClicked(event -> {
            if (imgPaths.size() <= 0) {
                initImageView();
            } else {
                if (currentImgIndex >= imgPaths.size() - 1) {
                    currentImgIndex = imgPaths.size() - 1;
                } else {
                    currentImgIndex++;
                }
                imageView.setImage(getImage(imgPaths.get(currentImgIndex)));
                updateImageViewLayout();
            }
        });
    }

    private void initImageViewLast() {
        Image last = new Image("icons/left-circle.png");
        imageViewLast.setImage(last);
        imageViewLast.setOnMouseClicked(event -> {
            if (imgPaths.size() <= 0) {
                initImageView();
            } else {
                if (currentImgIndex <= 0) {
                    currentImgIndex = 0;
                } else {
                    currentImgIndex--;
                }
                imageView.setImage(getImage(imgPaths.get(currentImgIndex)));
                updateImageViewLayout();
            }
        });
    }

    private Image getImage(String url) {
        if (url.contains(":") && !url.contains("file:")) {
            return new Image("file:" + url);
        }
        return new Image(url);
    }

    private void initImageReload() {
        Image reload = new Image("icons/reload.png");
        imageViewReload.setImage(reload);
        imageViewReload.setOnMouseClicked(event -> {
            if (imgPaths.size() <= 0) {
                imageView.setImage(getImage(DEFAULT_IMAGE_URL));
            } else {
                if (currentImgIndex < imgPaths.size()) {
                    imageView.setImage(getImage(imgPaths.get(currentImgIndex)));
                } else {
                    imageView.setImage(getImage(DEFAULT_IMAGE_URL));
                }
            }
            updateImageViewSize();
            updateImageViewLayout();
        });
    }

    private void initAnchorPaneRoot() {
        anchorPaneRoot.widthProperty().addListener((observable, oldValue, newValue) -> {
            updateImageViewLayout();
            updateFlowPaneLayout();
        });
        anchorPaneRoot.heightProperty().addListener((observable, oldValue, newValue) -> {
            updateImageViewLayout();
            updateFlowPaneLayout();
        });
    }

    private void initImageViewNice() {
        Image nice = new Image("icons/nice.png");
        imageViewNice.setImage(nice);
        imageViewNice.setOnMouseClicked(event -> {
            updateImageViewSize();
            updateImageViewLayout();
        });
    }

    private void updateImageViewSize() {
        double width = anchorPaneRoot.getWidth();
        double height = anchorPaneRoot.getHeight();
        Image image = imageView.getImage();
        double imageHeight = image.getHeight();
        double imageWidth = image.getWidth();
        double fitImageWidth;
        double fitImageHeight;
        if (imageHeight < height && imageWidth < width) {
            fitImageWidth = imageWidth;
            fitImageHeight = imageHeight;
        } else {
            //若被加载图片相对容器更宽，更矮：
            //即当k2 > k1时，W'' = W, H'' = W / k2;
            //若被加载图片相对容器更高，更窄：
            //即当k2 < K1时，H'' = H, W'' = H * k2;
            //若被加载图片宽高比与容器相当：
            //即当k2 = K1时，W'' = W, H'' = H。
            double k1 = width / height;
            double k2 = imageWidth / imageHeight;
            if (k2 > k1) {
                fitImageWidth = width;
                fitImageHeight = width / k2;
            } else if (k2 < k1) {
                fitImageHeight = height;
                fitImageWidth = height * k2;
            } else {
                fitImageHeight = height;
                fitImageWidth = width;
            }
        }
        imageView.setFitWidth(fitImageWidth);
        imageView.setFitHeight(fitImageHeight);
    }

    private void initImageViewSmall() {
        Image small = new Image("icons/minus-circle.png");
        imageViewSmall.setImage(small);
        imageViewSmall.setOnMouseClicked(event -> {
            double fitHeight = imageView.getFitHeight();
            double fitWidth = imageView.getFitWidth();
            imageView.setFitWidth(fitWidth * (1 - added));
            imageView.setFitHeight(fitHeight * (1 - added));
            updateImageViewLayout();
        });
    }

    private void initImageViewBig() {
        Image big = new Image("icons/plus-circle.png");
        imageViewBig.setImage(big);
        imageViewBig.setOnMouseClicked(event -> {
            double fitHeight = imageView.getFitHeight();
            double fitWidth = imageView.getFitWidth();
            imageView.setFitWidth(fitWidth * (1 + added));
            imageView.setFitHeight(fitHeight * (1 + added));
            updateImageViewLayout();
        });
    }

    private void initFlowPane() {
        String styleFull = "-fx-background-color: rgba(255,255,255,1);";
        String styleTrans = "-fx-background-color: rgba(255,255,255,0);";
        flowPaneTool.setOnMouseEntered(event -> {
            flowPaneTool.setStyle(styleFull);
            flowPaneTool.getChildren().forEach(child -> {
                child.setStyle(styleFull);
                if (child instanceof ImageView) {
                    ImageView img = (ImageView) child;
                    img.setOpacity(1);
                }
            });
        });
        flowPaneTool.setOnMouseExited(event -> {
            flowPaneTool.setStyle(styleTrans);
            flowPaneTool.getChildren().forEach(child -> {
                child.setStyle(styleTrans);
                if (child instanceof ImageView) {
                    ImageView img = (ImageView) child;
                    img.setOpacity(0);
                }
            });
        });
        updateFlowPaneLayout();
    }

    private void initImgList() {
    }

    public void initImageView() {
        if (currentImgIndex >= 0 && currentImgIndex < imgPaths.size()) {
            imageView.setImage(getImage(imgPaths.get(currentImgIndex)));
        } else {
            imageView.setImage(getImage(DEFAULT_IMAGE_URL));
        }
        updateImageViewLayout();
    }

    private void updateImageViewLayout() {
        double fitHeight = imageView.getFitHeight();
        double fitWidth = imageView.getFitWidth();
        double layoutX = anchorPaneRoot.getLayoutX();
        double layoutY = anchorPaneRoot.getLayoutY();
        double width = anchorPaneRoot.getWidth();
        double height = anchorPaneRoot.getHeight();

        double centerX = layoutX + width / 2;
        double centerY = layoutY + height / 2;

        double imageX = centerX - fitWidth / 2;
        double imageY = centerY - fitHeight / 2;
        imageView.setLayoutX(imageX);
        imageView.setLayoutY(imageY);
    }

    private void updateFlowPaneLayout() {
        double width = anchorPaneRoot.getWidth();
        double height = anchorPaneRoot.getHeight();

        flowPaneTool.setPrefHeight(30);
        flowPaneTool.setPrefWidth(width);
        flowPaneTool.setLayoutY(height - flowPaneTool.getPrefHeight());

        updateListViewInfoLayout();
    }

    private void updateListViewInfoLayout() {
        double listViewInfoWidth = listViewInfo.getPrefWidth();
        double listViewInfoHeight = listViewInfo.getPrefHeight();
        Point2D point2D = imageViewInfo.localToScene(0, 0);
        double imageViewInfoLayoutX = point2D.getX();
        double imageViewInfoLayoutY = point2D.getY();
        double imageViewInfoFitWidth = imageViewInfo.getFitWidth();
        double listViewInfoLayoutY = imageViewInfoLayoutY - listViewInfoHeight;
        double listViewInfoLayoutX = imageViewInfoLayoutX + imageViewInfoFitWidth / 2 - listViewInfoWidth / 2;
        listViewInfo.setLayoutX(listViewInfoLayoutX);
        listViewInfo.setLayoutY(listViewInfoLayoutY);
    }

    public void setStage(Stage stage) {
        this.stage = stage;
    }
}
